package com.leador.map.location;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Looper;
import android.telephony.CellLocation;
import android.telephony.NeighboringCellInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;

import com.leador.map.api.location.core.ClientInfoUtil;
import com.leador.map.location.cell.Cdma;
import com.leador.map.location.cell.Gsm;
import com.leador.map.location.log.Log;
import com.leador.map.location.log.Storage;
import com.leador.map.location.protocol.CellInfoBean;
import com.leador.map.location.protocol.ClientInfo;
import com.leador.map.location.protocol.DataInfo;
import com.leador.map.location.protocol.LocationRequest;
import com.leador.map.location.protocol.WifiInfoBean;
import com.leador.map.location.provider.DefaultLocationProvider;
import com.leador.map.location.provider.ILocationProvider;
import com.leador.map.location.util.Des;
import com.leador.map.location.util.NetUtil;
import com.leador.map.location.util.Utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

/**
 * 定位服务
 *
 * @version 1.0
 */
public class LocationService implements ILocationService {
    private static LocationService locationService = null;
    //
    private Context ctx = null;
    private int iCellType = Const.iDefCellType;

    private ConnectivityManager cm = null;
    private WifiManager wifiManager = null;
    private TelephonyManager tm = null;
    private LocationManager lm = null;

    private LocationListener locListenerGps = null;
    private LocationListener locListenerNet = null;
    private GpsStatus.Listener gpsStatusListener = null;

    private float fGpsSig = 0f;
    private Location locGps = null;
    private Location locNet = null;
    private long lGpsLocal = 0l;

    private List<Gsm> lstGsm = new ArrayList();
    private List<Cdma> lstCdma = new ArrayList();

    private List<ScanResult> lstScanResult = new ArrayList();

    private Des des = new Des();

    private PhoneStateListener psl = null;
    private int iCellSig = Const.iDefCellSig;

    private MyBroadcastReceiver myBroadcastRece = new MyBroadcastReceiver();
    //
    private WifiInfo wiAccess = null;
    private String strLastLocReq = null;
    private LocationInfo locationInfoLast = null;
    private long lLastResp = 0l;



    private long lastLocRequestTime = 0l;
    private long lLastLog = 0l;
    private boolean bPendGps = false;
    private boolean bCellOrGpsLocChanged = false;
    private long lLastCellLocChange = 0l;
    private long lastCellLocUpdateTime = 0l;
    private long lLastGpsEvent = 0l;
    private long lastWifiUpdateTime = 0l;
    private boolean bReqNet = true;

    private int locCount = 0;
    private String strMac = null;
    private GpsStatus gpsStatus = null;



    private ILocationProvider locationProvider;

    private LocationService() {
        //
    }

    /**
     * 获取定位接口实例
     *
     * @return 获取到的实例
     */
    public synchronized static ILocationService getInstance() {
        synchronized (LocationService.class) {
            if (locationService == null) {
                locationService = new LocationService();
            }
        }
        return locationService;
    }

    /**
     * 初始化
     *
     * @param ctx 上下文
     */
    public void init(Context ctx) {
        this.ctx = ctx.getApplicationContext();
        //
        Utils.toast(this.ctx, "in debug mode, only for test");
        Utils.writeCat("version ", getVersion());
        //
        locGps = new Location(LocationManager.GPS_PROVIDER);
        locNet = new Location(LocationManager.NETWORK_PROVIDER);
        //初始化Wifi
        initWifiListener();
        //初始化移动通讯
        initPhoneStateListener();
        //默认使用的服务端
        locationProvider=new DefaultLocationProvider(this,ctx,cm);
    }

    /**
     * 设置使用/禁用GPS(仅在用户勾选了[位置和安全]中的[使用GPS卫星]时本设置有效， 在使用时会启动手机GPS设备)
     *
     * @param bUseGps 使用-true,不适用-false
     */
    @Override
    public void setUseGps(boolean bUseGps) {
        //GPS状态为发生变化则不继续处理
        if (bUseGps == Const.bUseGps || bPendGps) {
            return;
        }
        bPendGps = true;
        if (lm == null) {
            lm = (LocationManager) Utils.getService(ctx, Context.LOCATION_SERVICE);
        }
        //
        Const.bUseGps = bUseGps;
        //
        if (bUseGps) {
            initGpsLocListener();
            initGpsStatusListener();
            Utils.writeCat("use gps");
        } else {
            removeGpsLocListener();
            removeGpsStatusListener();
            Utils.writeCat("not use gps");
        }
        bPendGps = false;
    }

    /**
     * 上传/停止上传ZIP压缩日志
     *
     * @param bUp true-上传,false-停止
     */
    @Override
    public void setUpZip(boolean bUp) {
        if (bUp) {
            Storage.upZip(ctx.getApplicationContext());
        } else {
            Storage.stopUpZip(ctx.getApplicationContext());
        }

    }

    /**
     * 设置使用/禁用缓存
     *
     * @param bUseCache 使用缓存-true，不使用-false
     */
    @Override
    public void setUseCache(boolean bUseCache) {
        Const.bUseCache = bUseCache;
        if (Const.bUseCache) {
            Utils.writeCat("set use cache");
        } else {
            Utils.writeCat("set not use cache");
        }
    }

    /**
     * 立即进行一次定位， 获取位置
     *
     * @return 定位到的位置
     */
    @Override
    public synchronized LocationInfo getLocation() throws Exception {
        locCount++;
        //第一次定位，等待WIFI一点时间
        if (locCount == 1 && wifiManager.isWifiEnabled()) {
            Utils.writeCat("first loc, wait wifi ", Const.lWaitWifi, "ms");
            try {
                Thread.sleep(Const.lWaitWifi);
            } catch (Exception e) {
                Utils.printE(e);
            }
        }
        //判断请求频率是否过快
        if (locReqFreq(lLastResp)) {
            if (locationInfoLast != null) {
                lLastResp = Utils.getTime();
                return locationInfoLast;
            }
        }
        //
        String strKey = getReqCacheKey();
        Utils.writeCat("postXml key:", strKey);
        if (strKey.equals("")) {
            Utils.writeCat("no postXml key, pass");
            return null;
        }
        //
        String strLocReq = "";
        //获取周边基站&Wifi信息
        StringBuilder sbNb = getReqNearBys();
        //从缓存中获取定位信息
        LocationInfo locationInfo = Cache.getInstance().get(strKey, sbNb);
        //
        if (locationInfo == null) {
            if (strKey.indexOf("#" + LocationManager.GPS_PROVIDER) != -1) {
                Utils.writeCat("get loc from gps");
                bReqNet = false;
                strLocReq = getEncryptLocReq();
                locationInfoLast = getGpsLoc(locGps);
            } else {
                bReqNet = locCount > Const.intNetWaitNum ? true : false;
                //
                strLocReq = getEncryptLocReq();
                if (strLocReq.equals(strLastLocReq)) {
                    if (locationInfoLast != null) {
                        Utils.writeCat("block same postXml");
                        lLastResp = Utils.getTime();
                        return locationInfoLast;
                    }
                }
                strLastLocReq = strLocReq;
                Utils.writeCat("get loc from locationService");
                //
                LocationInfo locationInfoNow = getNetworkLocation(strLocReq);
                //
                if (Utils.distAccept(locationInfoNow, locationInfoLast)) {
                    locationInfoLast = locationInfoNow;
                }
            }
        } else if (locNeedUpdate()) {
            //缓存中存在，但是需要更新
            Utils.writeCat("force loc");
            Utils.writeCat("get loc from locationService");
            bReqNet = true;
            strLocReq = getEncryptLocReq();
            if (strLocReq.equals(strLastLocReq)) {
                if (locationInfoLast != null) {
                    Utils.writeCat("block same postXml");
                    lLastResp = Utils.getTime();
                    return locationInfoLast;
                }
            }
            strLastLocReq = strLocReq;
            locationInfoLast = getNetworkLocation(strLocReq);
        } else {
            if (Const.bDebug) {
                bReqNet = false;
                getEncryptLocReq();
            }
            locationInfoLast = locationInfo;
        }
        Cache.getInstance().add(strKey, locationInfoLast, sbNb);
        sbNb.delete(0, sbNb.length());
        sbNb = null;
        lLastResp = Utils.getTime();
        return locationInfoLast;
    }

    /**
     * 设置定位授权（格式为src##license##clientid）
     *
     * @param lic
     * @return void
     */
    @Override
    public void setAuth(String lic) {
        if (lic == null || lic.indexOf("##") == -1) {
            Utils.writeCat("illegal auth, error 1");
            return;
        }
        String[] sa = lic.split("##");
        if (sa.length != 3) {
            Utils.writeCat("illegal auth, error 2");
            return;
        }
        //
        Const.strSrc = sa[0];
        Const.strLicense = sa[1];
        Const.strClientId = sa[2];
    }

    /**
     * 销毁APS定位相关资源
     *
     * @return 无
     */
    @Override
    public void destroy() {
        Utils.writeCat("destroy locationService");
        //setUpZip(false);
        try {
            ctx.unregisterReceiver(myBroadcastRece);
        } catch (Exception e) {
            Utils.writeCat("unregister broadcast rece fail");
        } finally {
            myBroadcastRece = null;
        }
        //
        removeGpsLocListener();
        removeNetLocListener();
        removeGpsStatusListener();
        //
        try {
            tm.listen(psl, PhoneStateListener.LISTEN_NONE);
        } catch (Exception e) {
            Utils.printE(e);
        }
        //
        Cache.getInstance().resetCache();
        bPendGps = false;
        lLastResp = 0l;
        lstGsm.clear();
        lstCdma.clear();
        iCellSig = Const.iDefCellSig;
        resetWifiData();
        strLastLocReq = null;
        locationInfoLast = null;
        resetGpsData();
        gpsStatus = null;
        ctx = null;
        tm = null;
        lm = null;
        locListenerGps = null;
        gpsStatusListener = null;
        locationService = null;
        System.gc();
    }

    /**
     * 获取定位插件版本
     *
     * @return String
     */
    @Override
    public String getVersion() {
        return Const.strVer;
    }

    /**
     * 初始化Wifi监听器
     *
     * @return
     */
    private void initWifiListener() {
        wifiManager = (WifiManager) Utils.getService(ctx, Context.WIFI_SERVICE);
        //强制刷新一次Wifi
        updateWifi();
        //注册WIFI状态变化
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        //
        ctx.registerReceiver(myBroadcastRece, intentFilter);
    }

    /**
     * 初始化PHONESTATE监听器
     *
     */
    private void initPhoneStateListener() {

        cm = (ConnectivityManager) Utils.getService(ctx, Context.CONNECTIVITY_SERVICE);
        CellLocation.requestLocationUpdate();
        //
        tm = (TelephonyManager) Utils.getService(ctx, Context.TELEPHONY_SERVICE);
        psl = new PhoneStateListener() {
            @Override
            public void onCellLocationChanged(CellLocation cellLoc) {
                Utils.writeCat("cell loc changed");
                bCellOrGpsLocChanged = true;
                if (cellLocChangeFast()) {
                    Utils.writeCat("cell loc change too fast, ignore");
                    return;
                }
                handleCellLocChange(cellLoc);
                lLastCellLocChange = Utils.getTime();
            }

            /**
             * 判断CELLLOCATION是否变化得太快
             *
             * @return
             */
            private boolean cellLocChangeFast() {
                if (lLastCellLocChange == 0l) {
                    return false;
                }
                long l = Utils.getTime() - lLastCellLocChange;
                Utils.writeCat("cell loc change time#", l, "ms");
                return (l < Const.lMinCellChange);
            }

            @Override
            public void onSignalStrengthsChanged(SignalStrength sigStren) {
                Utils.writeCat("cell sig stren changed");
                handleCellSigStrenChange(sigStren);
            }

            @Override
            public void onServiceStateChanged(ServiceState servState) {
                int iState = servState.getState();
                switch (iState) {
                    case ServiceState.STATE_OUT_OF_SERVICE:
                        lstGsm.clear();
                        lstCdma.clear();
                        iCellSig = Const.iDefCellSig;
                        break;
                    default:
                        break;
                }
            }
        };
        //
        tm.listen(psl, PhoneStateListener.LISTEN_CELL_LOCATION
                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
    }

    /**
     * 初始化GPSSTATUS监听器
     *
     * @return
     */
    private void initGpsStatusListener() {
        if (!Utils.hasGPSProvider(lm)) {
            return;
        }
        removeGpsStatusListener();
        gpsStatusListener = new GpsStatus.Listener() {
            @Override
            public void onGpsStatusChanged(int iEvent) {
                handleGpsStatusChange(iEvent);
            }
        };
        lm.addGpsStatusListener(gpsStatusListener);
    }

    /**
     * 处理手机基站切换的回调
     *
     * @param cellLoc
     * @return
     */
    private synchronized void handleCellLocChange(CellLocation cellLoc) {
        int iCellLocType = Utils.getCellType(cellLoc, ctx);
        switch (iCellLocType) {
            case Const.iGsmType:
                Utils.writeCat("cell loc type is gsm");
                if (cellLoc != null && tm != null) {
                    handleGsmLocChange(cellLoc);
                }
                break;
            case Const.iCdmaType:
                Utils.writeCat("cell loc type is cdma");
                if (cellLoc != null) {
                    handleCdmaLocChange(cellLoc);
                }
                break;
            default:
                Utils.writeCat("cell loc type is ", iCellLocType);
                break;
        }
    }

    /**
     * 判断定位请求是否过于频繁
     *
     * @param lLastResp
     * @return boolean 频繁-true，不频繁-false
     */
    private boolean locReqFreq(long lLastResp) {
        boolean bFreq = false;
        long l = Utils.getTime() - lLastResp;
        if (l < Const.lMinReq) {
            Utils.writeCat("block frequent postXml");
            bFreq = true;
        }
        return bFreq;
    }

    /**
     * 判断是否需要采集
     *
     * @return boolean
     */
    private boolean needWriteLog() {
        boolean bNeedWriteLog = false;
        long l = Utils.getTime() - lLastLog;
        if (bCellOrGpsLocChanged) {
            Utils.writeCat("cell or gps loc changed, write log");
            bNeedWriteLog = true;
        }
        if (l < Const.lMinLog) {
            Utils.writeCat("block frequent write log");
            bNeedWriteLog = false;
        }
        bCellOrGpsLocChanged = false;
        return bNeedWriteLog;
    }

    /**
     * 获取定位请求的key
     *
     * @return 请求的key
     */
    private String getReqCacheKey() {
        if (Utils.airPlaneModeOn(ctx)) {
            Utils.writeCat("air plane mode on");
            iCellType = Const.iDefCellType;
            lstGsm.clear();
            lstCdma.clear();
        }
        String strKey = "";
        String strCacheType = "";
        if (Utils.coordInCN(locGps)) {
            strCacheType = LocationManager.GPS_PROVIDER;
        } else {
            strCacheType = LocationManager.NETWORK_PROVIDER;
        }
        if (wifiManager.isWifiEnabled()) {
            wiAccess = wifiManager.getConnectionInfo();
        } else {
            resetWifiData();
        }
        String strKeyType = "";
        switch (iCellType) {
            case Const.iGsmType:
                if (lstGsm.size() > 0) {
                    Gsm gsm = lstGsm.get(0);
                    StringBuilder sb = new StringBuilder();
                    sb.append(gsm.getMcc()).append("#");
                    sb.append(gsm.getMnc()).append("#");
                    sb.append(gsm.getLac()).append("#");
                    sb.append(gsm.getCid()).append("#");
                    sb.append(strCacheType).append("#");
                    if (lstScanResult.size() > 0 || wifiUseful(wiAccess)) {
                        strKeyType = "cellwifi";
                    } else {
                        strKeyType = "cell";
                    }
                    sb.append(strKeyType);
                    strKey = sb.toString();
                }
                break;
            case Const.iCdmaType:
                if (lstCdma.size() > 0) {
                    Cdma cdma = lstCdma.get(0);
                    StringBuilder sb = new StringBuilder();
                    sb.append(cdma.getMcc()).append("#");
                    sb.append(cdma.getMnc()).append("#");
                    sb.append(cdma.getSid()).append("#");
                    sb.append(cdma.getNid()).append("#");
                    sb.append(cdma.getBid()).append("#");
                    sb.append(strCacheType).append("#");
                    if (lstScanResult.size() > 0 || wifiUseful(wiAccess)) {
                        strKeyType = "cellwifi";
                    } else {
                        strKeyType = "cell";
                    }
                    sb.append(strKeyType);
                    strKey = sb.toString();
                }
                break;
            case Const.iDefCellType:
                if (lstScanResult.size() > 0 || wifiUseful(wiAccess)) {
                    strKey = "#wifi";
                }
                Utils.writeCat("cell type unknown");
            default:
                break;
        }
        return strKey;
    }

    /**
     * 判断WIFI信息是否有用
     *
     * @param wi
     * @return 有用-true
     *
     */
    private boolean wifiUseful(WifiInfo wi) {
        boolean bUseful = true;
        if (wi == null || wi.getBSSID() == null) {
            bUseful = false;
        } else if (wi.getBSSID().equals("00:00:00:00:00:00")) {
            bUseful = false;
        }
        return bUseful;
    }

    /**
     * 获取定位请求的周边信息
     *
     * 基站或者WIFI热点
     *
     * @return
     */
    private StringBuilder getReqNearBys() {
        if (Utils.airPlaneModeOn(ctx)) {
            iCellType = Const.iDefCellType;
            lstGsm.clear();
            lstCdma.clear();
        }
        StringBuilder sb = new StringBuilder(700);
        switch (iCellType) {
            case Const.iGsmType: {
                for (int i = 0; i < lstGsm.size(); i++) {
                    if (i == 0) {
                        continue;
                    }
                    Gsm gsm = lstGsm.get(i);
                    sb.append("#").append(gsm.getMnc());
                    sb.append("|").append(gsm.getLac());
                    sb.append("|").append(gsm.getCid());
                }
                break;
            }
            default: {
                break;
            }
        }
        if (strMac == null || strMac.length() < 1) {
            if (wiAccess != null) {
                strMac = wiAccess.getMacAddress();
                if (strMac == null || strMac.length() < 1) {
                    strMac = null;
                }
            }
        }
        if (wifiManager.isWifiEnabled()) {
            String strAccessBssid = "";
            if (wifiUseful(wiAccess)) {
                strAccessBssid = wiAccess.getBSSID();
            }
            boolean bAccessInNb = false;
            for (int i = 0; i < lstScanResult.size(); i++) {
                String strBssid = lstScanResult.get(i).BSSID;
                String strType = "nb";
                if (strAccessBssid.equals(strBssid)) {
                    strType = "access";
                    bAccessInNb = true;
                }
                sb.append(String.format("#%s,%s", strBssid, strType));
            }
            if (!bAccessInNb && strAccessBssid.length() > 0) {
                sb.append("#").append(strAccessBssid);
                sb.append(",access");
            }
        } else {
            resetWifiData();
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(0);
        }
        return sb;
    }

    /**
     * 获取向定位服务发起请求的明文字符串
     * 同时设置采集数据组装请求串
     *
     * @param log
     * @return StringBuilder
     */
    private synchronized String getLocReq(Log log) {
        //
        String strIsCdma = "0";
        //
        String strHasGps = "0";
        String strGpsLon = "0";
        String strGpsLat = "0";
        String strAccu = "0";
        //
        String strNetLon = "0";
        String strNetLat = "0";
        Const.strImei = ClientInfoUtil.getImei();
        Const.strImsi = ClientInfoUtil.getImsi();
        Const.strPhnum = ClientInfoUtil.getPhonenum();
        String strNettype = "";
        String strInftype = "";
        //
        if (iCellType == Const.iCdmaType) {
            strIsCdma = "1";
        }
        if (!gpsLocExpired()) {
            if (log != null) {
                log.setGps(locGps, fGpsSig);
            }
            if (locGps.getLongitude() > 0d) {
                strHasGps = "1";
                strGpsLon = Log.fmatStr(locGps.getLongitude(), "#.000000");
                strGpsLat = Log.fmatStr(locGps.getLatitude(), "#.000000");
                strAccu = Log.fmatStr(locGps.getAccuracy(), "#.0");
            }
        } else {
            Utils.writeCat("gps loc expired, reset it");
            resetGpsData();
        }
        if (bReqNet) {
            reqSystemNetLoc();
        }
        //从系统网络定位中获取位置
        strNetLon = String.valueOf(locNet.getLongitude());
        strNetLat = String.valueOf(locNet.getLatitude());
        //获取设备信息
        if (tm != null) {
            if (Const.strImei == null || Const.strImei.equals("")) {
                Const.strImei = tm.getDeviceId();
                if (Const.strImei == null) {
                    Const.strImei = "";
                }
            }
            if (Const.strImsi == null || Const.strImsi.equals("")) {
                Const.strImsi = tm.getSubscriberId();
                if (Const.strImsi == null) {
                    Const.strImsi = "";
                }
            }
            if (Const.strPhnum == null || Const.strPhnum.equals("")) {
                Const.strPhnum = tm.getLine1Number();
                if (Const.strPhnum == null) {
                    Const.strPhnum = "";
                }
            }
        }
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        if (NetUtil.getNetworkType(networkInfo) != -1) {
            strNettype = NetUtil.getNetType(tm);
            if (wifiManager.isWifiEnabled()) {
                if (wifiUseful(wiAccess)) {
                    strInftype = "2";
                } else {
                    strInftype = "1";
                }
            } else {
                resetWifiData();
            }
        } else {
            wiAccess = null;
        }
        //
        ClientInfo clientInfo=new ClientInfo();
        //
        clientInfo.setGps(strHasGps);
        clientInfo.setGlng(strGpsLon);
        clientInfo.setGlat(strGpsLat);
        clientInfo.setPrecision(strAccu);
        clientInfo.setNlng(strNetLon);
        clientInfo.setNlat(strNetLat);
        clientInfo.setSrc(Const.strSrc);
        clientInfo.setLicense(Const.strLicense);
        clientInfo.setClientid(Const.strClientId);
        clientInfo.setVersion(Const.strVer);
        clientInfo.setImei(Const.strImei);
        clientInfo.setImsi(Const.strImsi);
        clientInfo.setMac(strMac);
        clientInfo.setCdma(Integer.parseInt(strIsCdma));
        clientInfo.setSdkver(ClientInfoUtil.getSdkVersion());
        clientInfo.setDevice(ClientInfoUtil.getDevice());
        clientInfo.setManuf(ClientInfoUtil.getManufacturer());
        clientInfo.setModel(ClientInfoUtil.getModel());
        //
        DataInfo dataInfo=new DataInfo();
        dataInfo.setPhnum(Const.strPhnum);
        dataInfo.setNettype(strNettype);
        dataInfo.setInftype(strInftype);
        //主机站信息
        CellInfoBean cellInfoBean =new CellInfoBean();
        //临近基站信息
        List<CellInfoBean> nbs=new ArrayList();
        //开始协议拼装
        //1-设备客户端信息

        if (log != null) {
            log.imei = des.encrypt(Const.strImei);
            log.imsi = des.encrypt(Const.strImsi);
            log.mac = des.encrypt(strMac);
        }
        //2-基站信息
        if (lstGsm.size() > 0 || lstCdma.size() > 0) {

            switch (iCellType) {
                case Const.iGsmType:
                {
                    //GSM类型
                    if (log != null) {
                        log.setGsm(lstGsm);
                    }
                    //主基站

                    Gsm gsmTmp = lstGsm.get(0);

                    //
                    cellInfoBean.setMcc(Utils.getShort(gsmTmp.getMcc(), (short) -1));
                    cellInfoBean.setMnc(Utils.getShort(gsmTmp.getMnc(),(short)-1));
                    cellInfoBean.setLac(gsmTmp.getLac());
                    cellInfoBean.setCellid(gsmTmp.getCid());
                    cellInfoBean.setSignal((short)gsmTmp.getSig());
                    //临近基站
                    for (int i = 0; i < lstGsm.size(); i++) {
                        if (i == 0) {
                            continue;
                        }
                        gsmTmp = lstGsm.get(i);

                        //
                        CellInfoBean nbCellInfoBean =new CellInfoBean();
                        nbCellInfoBean.setLac(gsmTmp.getLac());
                        nbCellInfoBean.setCellid(gsmTmp.getCid());
                        nbCellInfoBean.setSignal((short)gsmTmp.getSig());
                        //
                        nbs.add(nbCellInfoBean);
                    }
                    break;
                }
                case Const.iCdmaType:
                {
                    //CDMA类型
                    if (log != null) {
                        log.setCdma(lstCdma);
                    }
                    Cdma cdma = lstCdma.get(0);

                    //主基站
                    cellInfoBean.setMcc(Short.parseShort(cdma.getMcc()));
                    cellInfoBean.setMnc((short) cdma.getSid());
                    cellInfoBean.setLac(cdma.getNid());
                    cellInfoBean.setCellid(cdma.getBid());
                    cellInfoBean.setSignal((short) cdma.getSig());
                    cellInfoBean.setLng(cdma.getLon());
                    cellInfoBean.setLat(cdma.getLat());
                    break;
                }
                default:
                    break;

            }
        }
        //3-WIFI热点信息
        WifiInfoBean mmac=new WifiInfoBean();
        List<WifiInfoBean> macs=new ArrayList();
        //
        if (wifiManager.isWifiEnabled()) {
            if (log != null) {
                log.setWifi(lstScanResult);
            }
            if (wifiUseful(wiAccess)) {

                //
                mmac.setMac(wiAccess.getBSSID());
                mmac.setSignal((short) wiAccess.getRssi());
                mmac.setName(wiAccess.getSSID());
            }

            for (int i = 0; i < lstScanResult.size(); i++) {
                ScanResult scanResult = lstScanResult.get(i);

                //
                WifiInfoBean wifi=new WifiInfoBean();
                wifi.setMac(scanResult.BSSID);
                wifi.setSignal((short) scanResult.level);
                wifi.setName(scanResult.SSID);
                macs.add(wifi);
            }
        } else {
            resetWifiData();
        }
        //

        //
        dataInfo.setCell(cellInfoBean);
        dataInfo.setNbs(nbs);
        dataInfo.setMmac(mmac);
        dataInfo.setMacs(macs);
        //
        LocationRequest locRequest=new LocationRequest();
        locRequest.setDi(dataInfo);
        locRequest.setHi(clientInfo);
        locRequest.setVer(Const.serverVersion);//协议版本
        //
        String sbReq=locationProvider.getRequest(locRequest);
        return sbReq;
    }

    /**
     * 对WIFI进行排序
     *
     * @param lstScanResult2
     * @return 无
     */
    @SuppressLint("UseSparseArrays")
    private void setWifiOrder(List<ScanResult> lstScanResult2) {
        if (lstScanResult2 == null || lstScanResult2.size() < 1) {
            return;
        }
        Utils.writeCat("set wifi order");
        HashMap<Integer, ScanResult> hashMap = new HashMap<Integer, ScanResult>();
        for (int i = 0; i < lstScanResult2.size(); i++) {
            ScanResult scanResult = lstScanResult2.get(i);
            if (!wifiSigFine(scanResult.level)) {
                continue;
            }
            if (scanResult.SSID != null) {
                scanResult.SSID = scanResult.SSID.replace("*", ".");
            } else {
                scanResult.SSID = "null";
            }
            hashMap.put(scanResult.level, scanResult);
            if (i > (Const.iMaxWifiInReq - 1)) {
                break;
            }
        }
        TreeMap<Integer, ScanResult> treeMap = null;
        treeMap = new TreeMap<Integer, ScanResult>(Collections.reverseOrder());
        treeMap.putAll(hashMap);
        lstScanResult2.clear();
        for (Object object : treeMap.keySet()) {
            lstScanResult2.add(treeMap.get(object));
        }
        hashMap.clear();
        hashMap = null;
        treeMap.clear();
        treeMap = null;
    }

    /**
     * 判断WIFI信号是否合规
     *
     * @param iLev
     * @return boolean
     */
    private boolean wifiSigFine(int iLev) {
        int innSigLev = WifiManager.calculateSignalLevel(iLev, 20);
        return innSigLev >= Const.iMinWifiLev;
    }

    /**
     * 获取向定位服务发起请求的加密字符串
     *
     * @return 加密的定位请求串
     */
    private synchronized String getEncryptLocReq() {
        //1-请求更新传感器信息
        if (cellLocNeedUpdate()) {
            CellLocation.requestLocationUpdate();
            lastCellLocUpdateTime = Utils.getTime();
            Utils.writeCat("force update cell loc");
        }
        if (wifiNeedUpdate()) {
            updateWifi();
        }
        //2-获取明码请求
        String locReq;
        if (needWriteLog()) {
            Utils.writeCat("write log");
            Log log = new Log();
            //
            locReq = getLocReq(log);
            Storage.getInstance().writeLog(log, ctx);
            log.destroy();
            lLastLog = Utils.getTime();
        } else {
            Utils.writeCat("not write log");
            locReq = getLocReq(null);
        }
        //
        Utils.writeCat("pre locationService postXml:", locReq.toString());
        //3-组合加密请求
        String locStr=this.locationProvider.getEncrptRequest(locReq);

        return locStr;
    }

    /**
     * 判断基站是否需要强制刷新
     *
     * @return 需要刷新返回true,否则返回false
     */
    private boolean cellLocNeedUpdate() {
        boolean bUpdate = true;
        if (Utils.airPlaneModeOn(ctx)) {
            bUpdate = false;
        } else if (lastCellLocUpdateTime == 0l) {
            bUpdate = false;
        } else if (Utils.getTime() - lastCellLocUpdateTime < Const.lMinCellUpdate) {
            bUpdate = false;
        }
        return bUpdate;
    }

    /**
     * 判断Wifi是否需要强制刷新
     *
     * @return 需要刷新返回true,否则返回false
     */
    private boolean wifiNeedUpdate() {
        boolean bUpdate = true;
        if (!wifiManager.isWifiEnabled()) {
            bUpdate = false;
        } else if (lastWifiUpdateTime == 0l) {
            bUpdate = false;
        } else if (Utils.getTime() - lastWifiUpdateTime < Const.lMinWifiUpdate) {
            bUpdate = false;
        }
        return bUpdate;
    }

    /**
     * 从GPS坐标中，获取定位结果
     *
     * @param locGps GPS位置信息
     * @return 定位结果
     */
    private  LocationInfo getGpsLoc(Location locGps) {
        //
        LocationInfo locationInfo = new LocationInfo();
        //
        locationInfo.setProvider(LocationManager.GPS_PROVIDER);
        double dLon = locGps.getLongitude();
        locationInfo.setLon(Double.valueOf(Log.fmatStr(dLon, "#.000000")));
        double dLat = locGps.getLatitude();
        locationInfo.setLat(Double.valueOf(Log.fmatStr(dLat, "#.000000")));
        float fAccu = locGps.getAccuracy();
        //
        locationInfo.setAccuracy(Float.valueOf(Log.fmatStr(fAccu, "#.0")));
        locationInfo.setSpeed(Float.valueOf(Log.fmatStr(locGps.getSpeed(), "#.0")));
        locationInfo.setBearing(Float.valueOf(Log.fmatStr(locGps.getBearing(), "#.0")));
        locationInfo.setTime(Utils.getTime());
        //
        if (!isLocCorrect(locationInfo)) {
            Utils.writeCat("gps loc not correct");
            return null;
        }
        return locationInfo;
    }

    /**
     * 向定位服务器发起定位，并获取定位结果
     *
     * @param reqContent
     * @return
     */
    private LocationInfo getNetworkLocation(String reqContent) throws Exception {

        //
        LocationInfo locationInfo=this.locationProvider.getNetworkLocation(reqContent);
        //
        return isLocCorrect(locationInfo) ? locationInfo : null;
    }

    /**
     * 判断定位结果是否正确
     *
     * @param locationInfo
     * @return boolean
     */
    public boolean isLocCorrect(LocationInfo locationInfo) {
        boolean bCorrect = true;
        if (locationInfo == null) {
            bCorrect = false;
        } else if (locationInfo.getRetype().equals("5")) {
            bCorrect = false;
        } else if (locationInfo.getRetype().equals("6")) {
            bCorrect = false;
        } else if (locationInfo.getLon() < 1d) {
            bCorrect = false;
        } else if (locationInfo.getProvider().equals(LocationManager.GPS_PROVIDER)) {
            if (locationInfo.getAccuracy() > 500f && wifiManager.isWifiEnabled()) {
                if (lstScanResult.size() > 0) {
                    Utils.writeCat("gps accu is too low");
                    bCorrect = false;
                }
            }
        }
        return bCorrect;
    }



    /**
     * 判断GPS位置是否过期
     *
     * @return boolean
     */
    private boolean gpsLocExpired() {
        boolean bExpired = false;
        long l = Utils.getTime() - lGpsLocal;
        if (lGpsLocal == 0l) {
            //
        } else if (lm == null) {
            bExpired = true;
        } else if (!lm.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {
            bExpired = true;
        } else if (l > Const.lMaxGps) {
            bExpired = true;
        }
        return bExpired;
    }

    /**
     * 判断是否需要立即强制定位
     *
     * @return boolean
     */
    private boolean locNeedUpdate() {
        if (lLastResp == 0l) {
            return false;
        }
        return Utils.getTime() - lastLocRequestTime > Const.lMaxReq;
    }

    /**
     * 设置基站的信号强度
     *
     * @param sigStren
     * @return 无
     */
    private void handleCellSigStrenChange(SignalStrength sigStren) {
        int iAsu = sigStren.getGsmSignalStrength();
        iCellSig = Utils.asu2Dbm(iAsu);
        switch (iCellType) {
            case Const.iGsmType:
                if (lstGsm.size() > 0) {
                    lstGsm.get(0).setSig(iCellSig);
                }
                break;
            case Const.iCdmaType:
                if (lstCdma.size() > 0) {
                    lstCdma.get(0).setSig(iCellSig);
                }
                break;
            default:
                break;
        }
    }

    /**
     * 初始化GPS监听器
     *
     */
    private void initGpsLocListener() {
        if (!Utils.hasGPSProvider(lm)) {
            Utils.writeCat("no gps provider");
            return;
        }
        removeGpsLocListener();
        locListenerGps = new LocationListener() {
            @Override
            public void onLocationChanged(android.location.Location location) {
                Utils.writeCat("gps loc changed");
                bCellOrGpsLocChanged = true;
                locGps = location;
                lGpsLocal = Utils.getTime();
            }

            @Override
            public void onProviderDisabled(String strProvider) {
                Utils.writeCat("gps provider disabled");
                resetGpsData();
            }

            @Override
            public void onProviderEnabled(String strProvider) {
                Utils.writeCat("gps provider enabled");
            }

            @Override
            public void onStatusChanged(String strProvider, int iStatus,
                                        android.os.Bundle bundleExtras) {
                switch (iStatus) {
                    case LocationProvider.AVAILABLE:
                        Utils.writeCat("gps available");
                        break;
                    case LocationProvider.OUT_OF_SERVICE:
                        Utils.writeCat("gps out of serv");
                        resetGpsData();
                        break;
                    case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        Utils.writeCat("gps tmp unavailable");
                        resetGpsData();
                        break;
                    default:
                        break;
                }
            }
        };
        if (Const.bAgps) {
            lm.sendExtraCommand(android.location.LocationManager.GPS_PROVIDER,
                    "force_xtra_injection", null);
        }
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, Const.lMinGps,
                Const.lMinGpsDist, locListenerGps, Looper.getMainLooper());
    }

    /**
     * 移除GPSLOCATION监听
     *
     * @return 无
     */
    private void removeGpsLocListener() {
        resetGpsData();
        try {
            if (locListenerGps != null) {
                lm.removeUpdates(locListenerGps);
            }
        } catch (Exception e) {
            Utils.printE(e);
        } finally {
            locListenerGps = null;
        }
    }

    /**
     * 移除NETWORKLOCATION监听
     *
     * @return 无
     */
    private void removeNetLocListener() {
        locNet = new android.location.Location(android.location.LocationManager.NETWORK_PROVIDER);
        try {
            if (locListenerNet != null) {
                lm.removeUpdates(locListenerNet);
            }
        } catch (Exception e) {
            Utils.printE(e);
        } finally {
            locListenerNet = null;
        }
    }

    /**
     * 移除GPSSTATUS监听
     *
     * @return 无
     */
    private void removeGpsStatusListener() {
        fGpsSig = 0f;
        try {
            if (gpsStatusListener != null) {
                lm.removeGpsStatusListener(gpsStatusListener);
            }
        } catch (Exception e) {
            Utils.printE(e);
        } finally {
            gpsStatusListener = null;
        }
    }

    /**
     * 处理手机基站切换的回调
     *
     * @param iEvent
     * @return 无
     */
    private void handleGpsStatusChange(int iEvent) {
        if (lm == null) {
            return;
        }
        if (!lm.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {
            return;
        }
        switch (iEvent) {
            case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                if (gpsEventFreq()) {
                    Utils.writeCat("gps event fren, block");
                    return;
                }
                lLastGpsEvent = Utils.getTime();
                Utils.writeCat("gps event satellite status");
                fGpsSig = 0f;
                gpsStatus = lm.getGpsStatus(null);
                int iMaxSatellite = gpsStatus.getMaxSatellites();
                Iterator<GpsSatellite> iter = null;
                iter = gpsStatus.getSatellites().iterator();
                int iCount = 0;
                while (iter.hasNext() && iCount <= iMaxSatellite) {
                    fGpsSig += iter.next().getSnr();
                    iCount++;
                }
                Utils.writeCat(iCount, "/", iMaxSatellite, " satellites");
                Utils.writeCat("gps signal ", fGpsSig);
                iter = null;
                break;
            case GpsStatus.GPS_EVENT_STOPPED:
                Utils.writeCat("gps event stopped");
                resetGpsData();
                break;
            default:
                break;
        }
    }

    /**
     * 判断GPSEVENT通知是否过于频繁
     *
     * @return boolean
     */
    private boolean gpsEventFreq() {
        if (lLastGpsEvent == 0l) {
            return false;
        }
        return (Utils.getTime() - lLastGpsEvent) < Const.lMinGpsEvent;
    }

    /**
     * 从CELLLOCATION中获取GSM
     *
     * @param cellLoc
     * @return Gsm
     */
    private Gsm getGsm(CellLocation cellLoc) {
        GsmCellLocation gsmLoc = (GsmCellLocation) cellLoc;
        String[] saMccMnc = Utils.getMccMnc(tm);
        Gsm gsm = new Gsm();
        gsm.setMcc(saMccMnc[0]);
        gsm.setMnc(saMccMnc[1]);
        gsm.setLac(gsmLoc.getLac());
        gsm.setCid(gsmLoc.getCid());
        gsm.setSig(iCellSig);
        return gsm;
    }

    /**
     * 从NEIGHBORINGCELLINFO中获取GSM
     *
     * @param nbCellInfo
     * @return Gsm
     */
    private Gsm getGsm(NeighboringCellInfo nbCellInfo) {
        String[] saMccMnc = Utils.getMccMnc(tm);
        Gsm gsm = new Gsm();
        gsm.setMcc(saMccMnc[0]);
        gsm.setMnc(saMccMnc[1]);
        gsm.setLac(nbCellInfo.getLac());
        gsm.setCid(nbCellInfo.getCid());
        int iRssi = nbCellInfo.getRssi();
        gsm.setSig(Utils.asu2Dbm(iRssi));
        return gsm;
    }

    /**
     * 处理GSM基站切换
     *
     * @param cellLoc
     * @return 无
     */
    private void handleGsmLocChange(CellLocation cellLoc) {
        if (((GsmCellLocation) cellLoc).getLac() == 0) {
            return;
        }
        List<NeighboringCellInfo> lstNbCellInfo = null;
        lstNbCellInfo = tm.getNeighboringCellInfo();
        iCellType = Const.iGsmType;
        lstGsm.clear();
        lstGsm.add(getGsm(cellLoc));
        for (NeighboringCellInfo nbCellInfo : lstNbCellInfo) {
            if (nbCellInfo.getCid() > 65534) {
                continue;
            }
            lstGsm.add(getGsm(nbCellInfo));
        }
    }

    /**
     * 处理CDMA基站切换
     *
     * @param cellLoc
     * @return 无
     */
    private void handleCdmaLocChange(CellLocation cellLoc) {
        CdmaCellLocation cdmaLoc = (CdmaCellLocation) cellLoc;
        iCellType = Const.iCdmaType;
        lstCdma.clear();
        String[] saMccMnc = Utils.getMccMnc(tm);
        Cdma cdma = new Cdma();
        cdma.setMcc(saMccMnc[0]);
        cdma.setMnc(saMccMnc[1]);
        cdma.setSid(cdmaLoc.getSystemId());
        cdma.setNid(cdmaLoc.getNetworkId());
        cdma.setBid((cdmaLoc.getBaseStationId()));
        cdma.setSig(iCellSig);
        cdma.setLat(cdmaLoc.getBaseStationLatitude());
        cdma.setLon(cdmaLoc.getBaseStationLongitude());
        lstCdma.add(cdma);
    }

    /**
     * 重置WIFI数据
     *
     * @return 无
     */
    private void resetWifiData() {
        lstScanResult.clear();
        wiAccess = null;
    }

    /**
     * 重置GPS数据
     *
     * @return
     */
    private void resetGpsData() {
        locGps.reset();
        fGpsSig = 0f;
        lGpsLocal = 0l;
    }

    /**
     * 强制刷新Wifi
     *
     */
    private void updateWifi() {
        if (wifiManager.isWifiEnabled()) {
            wifiManager.startScan();
            lastWifiUpdateTime = Utils.getTime();
            Utils.writeCat("force scan wifis");
        }
    }

    /**
     * 请求系统网络定位位置
     *
     * @return
     */
    private void reqSystemNetLoc() {
        locNet = new Location(LocationManager.NETWORK_PROVIDER);
        if (!Const.bNetLoc) {
            return;
        }
        if (lm == null) {
            lm = (LocationManager) Utils.getService(ctx, Context.LOCATION_SERVICE);
        }
        if (!Utils.hasNetworkProvider(lm)) {
            Utils.writeCat("no net provider found");
            return;
        }
        if (!lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Utils.writeCat("net provider disabled");
            return;
        }
        if (!wifiManager.isWifiEnabled() || lstScanResult.size() == 0) {
            Utils.writeCat("sys net loc only in wifis mode");
        }
        Utils.writeCat("get sys net loc");
        if (locListenerNet == null) {
            locListenerNet = new LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    Utils.writeCat("net loc changed");
                    locNet = location;
                }

                @Override
                public void onProviderDisabled(String strProvider) {
                    Utils.writeCat("net provider disabled");
                    locNet.reset();
                }

                @Override
                public void onProviderEnabled(String strProvider) {
                    Utils.writeCat("net provider enabled");
                }

                @Override
                public void onStatusChanged(String strProvider, int iStatus,
                                            Bundle bundleExtras) {
                    switch (iStatus) {
                        case LocationProvider.AVAILABLE:
                            Utils.writeCat("net available");
                            break;
                        case LocationProvider.OUT_OF_SERVICE:
                            Utils.writeCat("net out of serv");
                            locNet.reset();
                            break;
                        case LocationProvider.TEMPORARILY_UNAVAILABLE:
                            Utils.writeCat("net tmp unavailable");
                            locNet.reset();
                            break;
                        default:
                            break;
                    }
                }
            };
        }
        lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                Const.lMinNet, Const.lMinNetDis, locListenerNet,
                Looper.getMainLooper());
        try {
            Thread.sleep(Const.lWaitNet);
        } catch (InterruptedException e) {
            Utils.printE(e);
        }
        if (lm == null) {
            return;
        }
        lm.removeUpdates(locListenerNet);
    }



    /**
     * 广播接收类
     */
    private class MyBroadcastReceiver extends android.content.BroadcastReceiver {
        private MyBroadcastReceiver() {
            //
        }

        @Override
        public void onReceive(Context ctx, android.content.Intent intent) {
            String strAction = intent.getAction();
            if (strAction.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                lstScanResult = wifiManager.getScanResults();
                if (lstScanResult == null) {
                    lstScanResult = new ArrayList<ScanResult>();
                }
                setWifiOrder(lstScanResult);
                Utils.writeCat("found ", lstScanResult.size(), " wifis");
            } else if (strAction.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
                int iState = wifiManager.getWifiState();
                switch (iState) {
                    case WifiManager.WIFI_STATE_DISABLED:
                        resetWifiData();
                        break;
                    case WifiManager.WIFI_STATE_DISABLING:
                        resetWifiData();
                        break;
                    case WifiManager.WIFI_STATE_UNKNOWN:
                        resetWifiData();
                        break;
                    default:
                        break;
                }
            } else if (strAction.equals(Intent.ACTION_SCREEN_ON)) {
                CellLocation.requestLocationUpdate();
                updateWifi();
                Utils.writeCat("screen on");
            }
        }
    }

    public long getLastLocRequestTime() {
        return lastLocRequestTime;
    }

    public void setLastLocRequestTime(long lastLocRequestTime) {
        this.lastLocRequestTime = lastLocRequestTime;
    }
}